package org.dromara.exam.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.exam.domain.dto.TemplateCount;
import org.dromara.exam.domain.dto.TemplateImport;
import org.dromara.exam.domain.dto.TemplateTypeCount;
import org.dromara.exam.domain.entity.ExamTemplate;
import org.dromara.exam.domain.bo.*;
import org.dromara.exam.domain.vo.ExamTemplateVo;
import org.dromara.exam.enums.TagTypeEnum;
import org.dromara.exam.mapper.ExamTemplateMapper;
import org.dromara.exam.service.IExamTemplateService;
import org.dromara.exam.service.IExamTagRelService;
import org.dromara.exam.service.IExamTagService;
import org.dromara.exam.util.DoubaoScoringUtils;
import org.dromara.exam.util.QuestionTemplateExcelParseHelper;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;

import static org.dromara.exam.util.AttributeProcessUtils.processAnswer;
import static org.dromara.exam.util.DoubaoScoringUtils.generateQuestionListByDoubao;

/**
 * 题目Service业务层处理
 *
 * @author xiyin321
 * @date 2024-04-11
 */
@RequiredArgsConstructor
@Service
public class ExamTemplateServiceImpl implements IExamTemplateService {

    private final ExamTemplateMapper baseMapper;
    private final IExamTagRelService tagRelService;
    private final IExamTagService tagService;

    // region 查 相关方法

    /**
     * 根据ID查询题目详情
     *
     * @param templateId 题目ID
     * @return 题目视图对象
     */
    @Override
    public ExamTemplateVo queryById(Long templateId) {
        return baseMapper.selectVoById(templateId);
    }

    /**
     * 根据ID批量查询题目列表
     *
     * @param templateIds 题目ID数组
     * @return 题目视图对象列表
     */
    @Override
    public List<ExamTemplateVo> queryListByIds(Long[] templateIds) {
        LambdaQueryWrapper<ExamTemplate> lqw = Wrappers.lambdaQuery();
        lqw.in(ExamTemplate::getTemplateId, (Object[]) templateIds);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 分页查询题目列表
     *
     * @param bo        查询条件对象
     * @param pageQuery 分页参数
     * @return 分页结果对象
     */
    @Override
    public TableDataInfo<ExamTemplateVo> queryPage(ExamTemplateBo bo, PageQuery pageQuery) {
        // 转换标签名称到标签ID
        List<Long> tagIds = tagService.convertTagsToIds(bo.getTag());
        Page<ExamTemplateVo> result = baseMapper.selectQuestionVoPage(
            pageQuery.build(), buildQuestionQueryWrapper(bo),
            tagIds, bo.getTagMatchMode());
//        Page<ExamTemplateVo> result = baseMapper.selectVoPage(pageQuery.build(), this.buildQueryWrapper(bo));
        return TableDataInfo.build(result);
    }

    /**
     * 查询题目列表
     *
     * @param bo 查询条件对象
     * @return 题目视图对象列表
     */
    @Override
    public List<ExamTemplateVo> queryList(ExamTemplateBo bo) {
        return baseMapper.selectVoList(buildQueryWrapper(bo));
    }

    /**
     * 从题库中挑选题目
     *
     * @param repoId        题库ID
     * @param questionTypes 题目类型列表
     * @param tags          标签列表
     * @return 题目视图对象列表
     */
    @Override
    public List<ExamTemplateVo> pickTemplateList(Long repoId, List<String> questionTypes, List<String> tags) {
        return baseMapper.pickTemplateList(repoId, questionTypes, tags);
    }

    /**
     * 根据题库ID列表查询题库题目统计
     *
     * @param repoIds 题库ID列表
     * @return 题目统计对象
     */
    @Override
    public List<TemplateCount> queryTemplateCounts(List<Long> repoIds) {
        return baseMapper.queryVoCounts(repoIds);
    }

    /**
     * 根据题库ID列表查询题库题目类型统计
     *
     * @param repoIds 题库ID列表
     * @return 题目类型统计对象
     */
    @Override
    public List<TemplateTypeCount> queryTemplateTypeCounts(List<Long> repoIds) {
        return baseMapper.queryTemplateTypeCounts(repoIds);
    }


    /**
     * 根据题库ID查询题目数量
     *
     * @param repoId 题库ID
     * @return 题目数量
     */
    @Override
    public Long queryTemplateCountByRepoId(Long repoId) {
        return baseMapper.selectCount(new LambdaQueryWrapper<ExamTemplate>()
            .eq(ExamTemplate::getRepoId, repoId));
    }

    /**
     * 检查题库是否存在关联的模板
     *
     * @param repoId 题库ID
     * @return Boolean
     */
    @Override
    public Boolean checkRepoExistTemplate(List<Long> repoId) {
        return baseMapper.exists(new LambdaQueryWrapper<ExamTemplate>().in(ExamTemplate::getRepoId, repoId));
    }
    // endregion

    // region 增 相关方法

    /**
     * 新增题目
     *
     * @param bo 题目业务对象
     * @return 操作结果
     */
    @Override
    public Boolean insertByBo(ExamTemplateBo bo) {
        bo.setTemplateId(IdWorker.getId());
        bo.setTemplateName(bo.getTemplate().getTitle());
        bo.setQuestionType(bo.getTemplate().getType());
        bo.setAnswer(processAnswer(bo.getTemplate()));
        bo.setScore(BigDecimal.valueOf(bo.getTemplate().getAttribute().getExamScore()));
        bo.setOrderNum(bo.getTemplate().getOrderNum());
        bo.setTag(bo.getTemplate().getTags().toArray(new String[0]));
        if (!bo.getTemplate().getTags().isEmpty()) {
            tagService.processTags(bo.getTemplateId(), TagTypeEnum.TemplateType, bo.getTag());
        }
        ExamTemplate add = MapstructUtils.convert(bo, ExamTemplate.class);
        validEntityBeforeSave();
        return baseMapper.insert(add) > 0;
    }

    /**
     * 批量新增或更新题目
     *
     * @param templates 题目集合
     */
    @Override
    public void batchInsertOrUpdate(Collection<ExamTemplate> templates) {
        baseMapper.insertOrUpdateBatch(templates);
    }

    /**
     * 导入题目模板
     *
     * @param bo 题目导入业务对象
     */
    @Override
    public void importTemplate(ExamTemplateImportBo bo) {
        // 解析Excel文件获取题目列表
        bo.setTemplates(parseExcelToTemplate(bo.getFile()));
        ExamTemplateUpdateBo examTemplateUpdateBo = BeanUtil.copyProperties(bo, ExamTemplateUpdateBo.class);
        // 批量插入题目
        batchUpdateQuestionTemplate(examTemplateUpdateBo);
    }

    /**
     * 通过excel导入题目到编辑界面
     *
     * @param bo 题目导入业务对象
     */
    @Override
    public List<TemplateImport> importTemplateToEdit(ExamTemplateImportBo bo) {
        return parseExcelToTemplate(bo.getFile());
    }

    /**
     * 生成题目列表
     *
     * @param bo 题目生成业务对象
     * @return 结果包含题目列表
     */
    @Override
    public List<ExamTemplateVo> generateQuestionList(QuestionGenerateBo bo) {
        try {
            // 调用豆包API生成题目
            String resultStr = generateQuestionListByDoubao(bo);
            return DoubaoScoringUtils.parseQuestions(resultStr);
        } catch (Exception e) {
            throw new RuntimeException("生成题目失败", e);
        }
    }
    // endregion

    // region 改 相关方法

    /**
     * 更新题目信息
     *
     * @param bo 题目业务对象
     * @return 操作结果
     */
    @Override
    public Boolean updateByBo(ExamTemplateBo bo) {
        ExamTemplate update = MapstructUtils.convert(bo, ExamTemplate.class);
        validEntityBeforeSave();
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 批量更新题目模板（新增或修改）
     *
     * @param bo 题目更新业务对象
     * @return 操作结果
     */
    @Override
    public Boolean batchUpdateQuestionTemplate(ExamTemplateUpdateBo bo) {
        List<ExamTemplate> addList = new ArrayList<>();
        List<ExamTemplate> updateList = new ArrayList<>();

        bo.getTemplates().forEach(template -> {
            // 设置基础属性
            template.setTemplateName(template.getTemplate().getTitle());
            template.setQuestionType(template.getTemplate().getType());
            template.setOrderNum(template.getTemplate().getOrderNum());
            template.setScore(template.getTemplate().getAttribute().getExamScore());
            // 处理答案
            template.setAnswer(processAnswer(template.getTemplate()));
            if (!template.getTemplate().getTags().isEmpty()) {
                template.setTag(template.getTemplate().getTags().toArray(new String[0]));
            }
            if (template.getTemplateId() == null) {
                // 新增处理
                if (template.getRepoId() == null) {
                    template.setRepoId(bo.getRepoId());
                }
                template.setTemplateId(IdWorker.getId());
                template.getTemplate().setId(String.valueOf(template.getTemplateId()));
                addList.add(BeanUtil.copyProperties(template, ExamTemplate.class));
            } else {
                // 更新处理
                tagRelService.deleteById(template.getTemplateId());
                updateList.add(BeanUtil.copyProperties(template, ExamTemplate.class));
            }
            // 处理普通标签
            if (!template.getTemplate().getTags().isEmpty()) {
                tagService.processTags(template.getTemplateId(), TagTypeEnum.TemplateType, template.getTag());
            }
        });

        // 批量处理新增数据
        if (!addList.isEmpty()) {
            if (bo.getRepoId() != null) {
                addList.forEach(template -> {
                    template.setRepoId(bo.getRepoId());
                });
            }
            batchInsertOrUpdate(addList);
        }

        // 批量处理更新数据
        if (!updateList.isEmpty()) {
            if (bo.getRepoId() != null) {
                updateList.forEach(template -> {
                    template.setRepoId(bo.getRepoId());
                });
            }
            batchInsertOrUpdate(updateList);
        }

        return true;
    }
    // endregion

    // region 删 相关方法

    /**
     * 批量删除题目（带校验）
     *
     * @param ids     主键集合
     * @param isValid 是否进行关联校验
     * @return 操作结果
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // 删除关联的标签数据
            tagRelService.batchDeleteByRelIds(ids);
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 根据题库ID批量删除题目
     *
     * @param repoIds 题库ID列表
     * @return 操作结果
     */
    @Override
    public Boolean deleteBatchByRepoIds(List<Long> repoIds) {
        QueryWrapper<ExamTemplate> wrapper = new QueryWrapper<>();
        wrapper.eq("del_flag", "0");
        wrapper.in("repo_id", repoIds);
        return baseMapper.delete(wrapper) > 0;
    }
    // endregion

    // region 辅助方法

    /**
     * 构建题目查询条件包装器
     */
    private Wrapper<ExamTemplate> buildQuestionQueryWrapper(ExamTemplateBo bo) {
        return new QueryWrapper<ExamTemplate>()
            .eq("t.del_flag", "0")
            .eq(ObjectUtil.isNotNull(bo.getRepoId()), "t.repo_id", bo.getRepoId())
            .eq(ObjectUtil.isNotNull(bo.getQuestionType()), "t.question_type", bo.getQuestionType())
            .like(ObjectUtil.isNotNull(bo.getTemplateName()), "t.template_name", bo.getTemplateName());
    }

    /**
     * 构建Lambda查询条件
     */
    private LambdaQueryWrapper<ExamTemplate> buildQueryWrapper(ExamTemplateBo bo) {
        LambdaQueryWrapper<ExamTemplate> lqw = Wrappers.lambdaQuery();
        lqw.eq(ObjectUtil.isNotNull(bo.getRepoId()), ExamTemplate::getRepoId, bo.getRepoId())
            .eq(ObjectUtil.isNotNull(bo.getQuestionType()), ExamTemplate::getQuestionType, bo.getQuestionType())
            .eq(ObjectUtil.isNotNull(bo.getTemplateName()), ExamTemplate::getTemplateName, bo.getTemplateName())
            .orderByAsc(ExamTemplate::getOrderNum);
        return lqw;
    }

    /**
     * 解析Excel文件为题目模板
     */
    @SneakyThrows
    private List<TemplateImport> parseExcelToTemplate(MultipartFile file) {
        return new QuestionTemplateExcelParseHelper(file).parse();
    }

    /**
     * 保存前数据校验
     */
    private void validEntityBeforeSave() {
        // TODO 实现具体校验逻辑
    }
    // endregion
}
